package org.jvm.rtda.heap.classLoader;

import org.jvm.classpath.BootClassPath;
import org.jvm.rtda.Object;
import org.jvm.rtda.heap.Klass;
import org.jvm.rtda.thread.Thread;
import org.jvm.util.JvmUtil;

/**
 * JVM根类加载器，由JVM直接实现，不使用任何JavaCall
 *
 * @author 海燕
 * @date 2023/3/23
 */
public class BootKlassLoader extends AbstractKlassLoader {

    private BootClassPath classPath;

    public BootKlassLoader(BootClassPath classPath) {
        //根类加载器没有对应的java类加载器实例
        super(null);
        this.classPath = classPath;
    }

    public void init() {
        //先加载基本类的类对象
        loadBasicClass();
        //再加载基本类型的类
        loadPrimitiveClasses();
    }

    public Klass loadKlass(String klassName) {
        classPath.setUseExt(false);
        return loadKlass(klassName, null);
    }

    public Klass loadKlassWithExt(String klassName) {
        classPath.setUseExt(true);
        Klass klass = loadKlass(klassName, null);
        klassMap.remove(klass.getName());
        return klass;
    }

    /**
     * 根类加载器并不使用javaCall。thread为空
     *
     * @param klassName
     * @param thread
     * @return
     */
    @Override
    public Klass loadKlass(String klassName, Thread thread) {
        Klass klass = findLoadedKlass(klassName);
        if (klass != null) {
            return klass;
        }
        //检查数组类
        if (klassName.startsWith("[")) {
            klass = loadArrayClass(klassName);
            klassMap.put(klassName, klass);
            fillJavaClassAndJavaClassLoader(klass);
            return klass;
        }
        byte[] klassData = classPath.readClass(klassName);
        return defineKlass(klassName, klassData, null);
    }

    /**
     * 加载数组类
     *
     * @param klassName
     * @return
     */
    private Klass loadArrayClass(String klassName) {
        Klass arrayClass = Klass.newArrayKlass(klassName, this);
        arrayClass.setKlassLoader(this);
        return arrayClass;
    }

    /**
     * 类加载器初始化后，立刻对存量的类加载类对象
     */
    private void loadBasicClass() {
        loadKlass("java/lang/Class");
        /**
         * 加载java/lang/Class后，因为加载类需要先加载其父类。方法区中实际上有多个类
         */
        this.klassMap.values().forEach(item -> fillJavaClassAndJavaClassLoader(item));
        //预加载一些类，以供VM初始化和系统类加载器初始化
        for (String preKlass : preLoadKlass) {
            loadKlass(preKlass);
        }
    }

    /**
     * 基本类型也有对象的类，在这里进行加载
     */
    private void loadPrimitiveClasses() {
        JvmUtil.primitiveTypes.keySet().forEach(primitiveClassName -> {
            Klass primitiveClass = Klass.newPrimitiveClass(primitiveClassName, this);
            //基本类型的类不通过loadClass方法加载，需要手动放入方法区并加载类对象
            klassMap.put(primitiveClassName, primitiveClass);
            Klass classKlass = loadKlass("java/lang/Class");
            Object classObject = classKlass.newObject();
            classObject.setExtra(primitiveClass);
            primitiveClass.setjClass(classObject);
        });
    }

    private String[] preLoadKlass = new String[]{"java/security/cert/Certificate"
            , "java/util/Vector"
            , "java/util/Stack"
            , "sun/misc/Launcher"
            , "sun/misc/Launcher$Factory"
            , "sun/misc/Launcher$ExtClassLoader"
            , "sun/security/util/Debug"
            , "sun/security/action/GetPropertyAction"
            , "java/security/AccessController"
            , "java/lang/System"
            , "java/util/Properties"
            , "java/lang/Float"
            , "java/io/ObjectStreamField"
            , "java/util/Hashtable$Entry"
            , "java/lang/Math"
            , "java/lang/Double"
            , "java/util/Hashtable$EntrySet"
            , "java/util/Collections"
            , "java/util/Collections$EmptySet"
            , "java/util/Collections$EmptyList"
            , "java/util/Collections$EmptyMap"
            , "java/util/Collections$SynchronizedSet"
            , "java/util/Objects"
            , "java/util/Hashtable$Enumerator"
            , "sun/misc/Version"
            , "bejava/io/FileInputStream"
            , "java/io/FileDescriptor"
            , "java/io/FileDescriptor$1"
            , "sun/misc/SharedSecrets"
            , "sun/misc/Unsafe"
            , "sun/reflect/Reflection"
            , "java/util/HashMap"
            , "java/util/HashMap$Node"
            , "[Z"
            , "[B"
            , "[S"
            , "java/util/HashMap$TreeNode"
            , "[I"
            , "[J"
            , "[F"
            , "[D"
            , "[Ljava/lang/Object;"
            , "java/io/FileOutputStream"
            , "java/io/BufferedInputStream"
            , "java/util/concurrent/atomic/AtomicReferenceFieldUpdater"
            , "java/util/concurrent/atomic/AtomicReferenceFieldUpdater$AtomicReferenceFieldUpdaterImpl"
            , "java/util/concurrent/atomic/AtomicReferenceFieldUpdater$AtomicReferenceFieldUpdaterImpl$1"
            , "java/lang/Class$3"
            , "java/lang/Class$ReflectionData"
            , "java/lang/ref/SoftReference"
            , "java/lang/ref/Reference$Lock"
            , "java/lang/Thread"
            , "java/lang/StackTraceElement"
            , "java/lang/RuntimePermission"
            , "java/lang/ref/Reference$ReferenceHandler"
            , "java/lang/InterruptedException"
            , "java/util/ArrayList"
            , "java/util/Collections$UnmodifiableRandomAccessList"
            , "sun/misc/Cleaner"
            , "java/lang/ref/ReferenceQueue"
            , "java/lang/ref/ReferenceQueue$Null"
            , "java/lang/ref/ReferenceQueue$Lock"
            , "java/security/AccessControlContext"
            , "java/lang/ref/Reference$1"
            , "java/lang/Class$Atomic"
            , "java/lang/reflect/Constructor"
            , "java/security/ProtectionDomain"
            , "sun/reflect/generics/repository/ClassRepository"
            , "sun/reflect/ReflectionFactory"
            , "java/lang/Class$AnnotationData"
            , "sun/reflect/annotation/AnnotationType"
            , "java/lang/ClassValue$ClassValueMap"
            , "sun/reflect/ReflectionFactory$GetReflectionFactoryAction"
            , "java/lang/reflect/Modifier"
            , "java/lang/reflect/ReflectAccess"
            , "java/lang/reflect/ReflectPermission"
            , "sun/reflect/misc/ReflectUtil"
            , "java/lang/String$CaseInsensitiveComparator"
            , "java/util/Arrays"
            , "java/io/PrintStream"
            , "java/io/BufferedOutputStream"
            , "java/nio/charset/Charset"
            , "sun/nio/cs/StandardCharsets"
            , "sun/nio/cs/StandardCharsets$Aliases"
            , "sun/nio/cs/StandardCharsets$Classes"
            , "sun/nio/cs/StandardCharsets$Cache"
            , "java/lang/ThreadLocal"
            , "java/util/concurrent/atomic/AtomicInteger"
            , "java/lang/StringBuilder"
            , "sun/nio/cs/UTF_8"
            , "java/lang/Class$1"
            , "sun/reflect/ReflectionFactory$1"
            , "sun/reflect/ConstructorAccessorImpl"
            , "sun/reflect/NativeConstructorAccessorImpl"
            , "sun/reflect/DelegatingConstructorAccessorImpl"
            , "java/io/OutputStreamWriter"
            , "sun/nio/cs/StreamEncoder"
            , "sun/misc/URLClassPath$3"
            , "sun/misc/URLClassPath$FileLoader"
            , "java/lang/StringBuffer"
            , "java/lang/Short"
            , "sun/misc/URLClassPath$FileLoader$1"
            , "java/lang/Package"
            , "java/lang/ClassNotFoundException"
            , "java/security/PrivilegedActionException"
            , "sun/net/util/URLUtil"
            , "sun/nio/cs/UTF_8$Encoder"
            , "java/nio/charset/CodingErrorAction"
            , "java/nio/ByteBuffer"
            , "java/nio/HeapByteBuffer"
            , "java/nio/Bits"
            , "java/nio/ByteOrder"
            , "java/util/concurrent/atomic/AtomicLong"
            , "java/nio/Bits$1"
            , "java/io/BufferedWriter"
            , "java/lang/Runtime"
            , "java/io/File"
            , "java/io/DefaultFileSystem"
            , "java/io/UnixFileSystem"
            , "java/io/ExpiringCache"
            , "java/io/ExpiringCache$1"
            , "java/io/File$PathStatus"
            , "java/nio/file/Path"
            , "java/lang/Terminator"
            , "java/lang/Terminator$1"
            , "sun/misc/Signal"
            , "sun/misc/NativeSignalHandler"
            , "java/lang/Integer"
            , "java/lang/Integer$IntegerCache"
            , "sun/misc/OSEnvironment"
            , "java/lang/System$2"
            , "java/lang/ClassLoader$ParallelLoaders"
            , "java/util/WeakHashMap$Entry"
            , "java/util/Collections$SetFromMap"
            , "java/util/WeakHashMap$KeySet"
            , "java/lang/Boolean"
            , "java/net/URLClassLoader$7"
            , "sun/misc/Launcher$ExtClassLoader$1"
            , "java/net/URL"
            , "java/security/ProtectionDomain$JavaSecurityAccessImpl"
            , "java/security/ProtectionDomain$2"
            , "java/security/CodeSource"
            , "java/security/ProtectionDomain$Key"
            , "java/security/Principal"
            , "java/util/concurrent/ConcurrentHashMap"
            , "[Ljava/util/concurrent/ConcurrentHashMap$Segment;"
            , "[Ljava/util/concurrent/ConcurrentHashMap$Node;"
            , "[Ljava/util/concurrent/ConcurrentHashMap$CounterCell;"
            , "java/util/concurrent/ConcurrentHashMap$KeySetView"
            , "java/util/concurrent/ConcurrentHashMap$ValuesView"
            , "java/util/concurrent/ConcurrentHashMap$EntrySetView"
            , "java/util/concurrent/ConcurrentHashMap$CounterCell"
            , "sun/misc/URLClassPath"
            , "sun/net/www/protocol/jar/Handler"
            , "sun/misc/Launcher$AppClassLoader"
            , "sun/misc/Launcher$AppClassLoader$1"
            , "java/io/ExpiringCache$Entry"
            , "sun/net/www/ParseUtil"
            , "java/util/BitSet"
            , "java/lang/Byte"
            , "java/lang/Long"
            , "java/util/Locale"
            , "java/util/Locale$Cache"
            , "sun/util/locale/BaseLocale"
            , "sun/util/locale/BaseLocale$Cache"
            , "sun/util/locale/BaseLocale$Key"
            , "sun/util/locale/LocaleObjectCache$CacheEntry"
            , "java/util/concurrent/ConcurrentHashMap$Node"
            , "java/util/Locale$LocaleKey"
            , "sun/util/locale/LocaleUtils"
            , "java/lang/Character"
            , "java/lang/CharacterData"
            , "java/lang/CharacterDataLatin1"
            , "java/net/Parts"
            , "java/util/StringTokenizer"
            , "sun/net/www/protocol/file/Handler"
            , "sun/net/util/IPAddressUtil"
            , "java/lang/SystemClassLoaderAction"
            , "java/net/URLClassLoader$1"
            , "java/io/FileInputStream"
            , "sun/nio/ByteBuffered"
            , "java/io/FileInputStream$1"
            , "sun/misc/PerfCounter"
            , "java/nio/ByteBufferAsLongBufferB"
            , "java/security/Permissions"
            , "sun/net/www/protocol/file/FileURLConnection"
            , "sun/net/www/MessageHeader"
            , "java/io/FilePermission"
            , "java/io/FilePermission$1"
            , "java/io/FilePermissionCollection"
            , "java/security/AllPermission"
            , "java/security/UnresolvedPermission"
            , "java/security/BasicPermissionCollection"
            , "java/nio/CharBuffer"
            , "java/nio/HeapCharBuffer"
            , "java/nio/charset/CoderResult"
            , "java/nio/charset/CoderResult$1"
            , "java/nio/charset/CoderResult$2"
            , "sun/misc/Perf$GetPerfAction"
            , "sun/misc/Perf"
            , "sun/misc/PerfCounter$CoreCounters"
            , "sun/misc/MetaIndex"
            , "java/io/BufferedReader"
            , "java/io/FileReader"
            , "sun/nio/cs/StreamDecoder"
            , "sun/nio/cs/UTF_8$Decoder"
            , "java/lang/reflect/Array"
            , "java/io/WinNTFileSystem"
            , "sun/io/Win32ErrorMode"
            , "sun/misc/URLClassPath$JarLoader"
            , "java/util/zip/ZipFile"
            , "java/util/zip/ZipFile$1"
            , "sun/nio/cs/ThreadLocalCoders"
            , "sun/nio/cs/ThreadLocalCoders$1"
            , "sun/nio/cs/ThreadLocalCoders$2"
            , "java/lang/ThreadLocal$ThreadLocalMap"
            , "java/lang/ThreadLocal$ThreadLocalMap$Entry"
            , "jdk/internal/misc/TerminatingThreadLocal"

    };
}
